use std::{
    io::{self, Write},
    process::Command, thread, time::Duration,
};

use crate::disk::path_io;
use cross_rs::{fasttime::b2_time::TimeFT, string::extend::StringExentd};

/// lftp
const LFTP_BIN: &str = "lftp";

pub struct LFTPShell {
    pub account: String
}

impl LFTPShell {
    pub fn new(account: String) -> Self {
        Self {
            account,
        }
    }

    pub fn list_files_ftp(&self, dir_ftp: &str) -> Vec<(String, i64)> {
        // lftp 'jiangyinwhis:HBnh1h*1728(^%1HhTn1nk@10.36.53.63:1121' -e 'ls /SZL2/2023/0605; exit;'
    let mut cmd_order: Command = Command::new(LFTP_BIN);
    cmd_order
        .arg(&self.account)
        .arg("-e")
        .arg(format!("ls {dir_ftp}; exit;"));

    let output = cmd_order
        .output().unwrap();
    
    let mut buf = vec![];
    
    buf.write_all(&output.stdout).unwrap();

    let lines = String::from_utf8(buf).unwrap().split_arr('\n');

    let mut list_filename_size = vec![];

    for line in lines.iter() {
        // info!("{line}");
        let strs = line.replace("  ", " ").replace("  ", " ").replace("  ", " ").split_arr(' ');
        let len = strs.len();
        let size_str = match strs.get(len - 5) {
            Some(v) => v.clone(),
            None => continue,
        };
        let size = match size_str.parse::<i64>() {
            Ok(v) => v,
            Err(_) => continue,
        };
        list_filename_size.push((strs[strs.len() - 1].clone(), size));
    }

    info!("文件列表: {:?}", list_filename_size);

    list_filename_size
    /*
    -r--r--r-- 1 ftp ftp       14939512 Jun 05 17:40 am_hq_index.7z.001
    -r--r--r-- 1 ftp ftp            295 Jun 05 17:40 am_hq_order_agreement.7z.001
    -r--r--r-- 1 ftp ftp        3085695 Jun 05 17:40 am_hq_order_pledge.7z.001
    -r--r--r-- 1 ftp ftp            845 Jun 05 17:40 am_hq_order_refinance.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 17:41 am_hq_order_spot.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 17:41 am_hq_order_spot.7z.002
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 17:41 am_hq_order_spot.7z.003
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 17:42 am_hq_order_spot.7z.004
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 17:42 am_hq_order_spot.7z.005
    -r--r--r-- 1 ftp ftp       53419022 Jun 05 17:42 am_hq_order_spot.7z.006
    -r--r--r-- 1 ftp ftp         285754 Jun 05 17:42 am_hq_order_xianquan.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 17:42 am_hq_snap_spot.7z.001
    -r--r--r-- 1 ftp ftp       34457979 Jun 05 17:42 am_hq_snap_spot.7z.002
    -r--r--r-- 1 ftp ftp            233 Jun 05 17:42 am_hq_trade_agreement.7z.001
    -r--r--r-- 1 ftp ftp        2982213 Jun 05 18:06 am_hq_trade_pledge.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:02 am_hq_trade_spot.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:03 am_hq_trade_spot.7z.002
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:03 am_hq_trade_spot.7z.003
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:03 am_hq_trade_spot.7z.004
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:03 am_hq_trade_spot.7z.005
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:04 am_hq_trade_spot.7z.006
    -r--r--r-- 1 ftp ftp       22304560 Jun 05 18:04 am_hq_trade_spot.7z.007
    -r--r--r-- 1 ftp ftp          21439 Jun 05 18:04 am_hq_trade_xianquan.7z.001
    -r--r--r-- 1 ftp ftp        2372646 Jun 05 18:04 am_snap_bond.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:04 am_snap_level_spot.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:04 am_snap_level_spot.7z.002
    -r--r--r-- 1 ftp ftp       42934800 Jun 05 18:04 am_snap_level_spot.7z.003
    -r--r--r-- 1 ftp ftp        3399521 Jun 05 18:04 am_stock_status.7z.001
    -r--r--r-- 1 ftp ftp        1354673 Jun 05 18:04 pm_hq_closesnap.7z.001
    -r--r--r-- 1 ftp ftp       14596011 Jun 05 18:04 pm_hq_index.7z.001
    -r--r--r-- 1 ftp ftp            317 Jun 05 18:04 pm_hq_order_agreement.7z.001
    -r--r--r-- 1 ftp ftp        7376711 Jun 05 18:04 pm_hq_order_pledge.7z.001
    -r--r--r-- 1 ftp ftp            236 Jun 05 18:04 pm_hq_order_refinance.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:04 pm_hq_order_spot.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:05 pm_hq_order_spot.7z.002
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:05 pm_hq_order_spot.7z.003
    -r--r--r-- 1 ftp ftp       21866052 Jun 05 18:05 pm_hq_order_spot.7z.004
    -r--r--r-- 1 ftp ftp          71494 Jun 05 18:05 pm_hq_order_xianquan.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:05 pm_hq_snap_spot.7z.001
    -r--r--r-- 1 ftp ftp       18607355 Jun 05 18:05 pm_hq_snap_spot.7z.002
    -r--r--r-- 1 ftp ftp        8445865 Jun 05 18:05 pm_hq_trade_pledge.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:05 pm_hq_trade_spot.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:06 pm_hq_trade_spot.7z.002
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:06 pm_hq_trade_spot.7z.003
    -r--r--r-- 1 ftp ftp       72156284 Jun 05 18:06 pm_hq_trade_spot.7z.004
    -r--r--r-- 1 ftp ftp          18760 Jun 05 18:06 pm_hq_trade_xianquan.7z.001
    -r--r--r-- 1 ftp ftp        2508670 Jun 05 18:06 pm_snap_bond.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:07 pm_snap_level_spot.7z.001
    -r--r--r-- 1 ftp ftp       75497472 Jun 05 18:07 pm_snap_level_spot.7z.002
    -r--r--r-- 1 ftp ftp        6847329 Jun 05 18:07 pm_snap_level_spot.7z.003
    -r--r--r-- 1 ftp ftp        3561919 Jun 05 18:07 pm_stock_status.7z.001
    -r--r--r-- 1 ftp ftp       23168549 Jun 05 18:07 securities_20230605.xml
    */
        

    }


    /// 将整个ftp文件夹下载到本地, 会做文件列表检查
    /// 输入参数格式见函数体
    pub fn download_ftpdir(&self, dir_ftp: &str, dir_local: &str, count_retry: u32) -> usize {
        // lftp 'jiangyinwhis:HBnh1h*1728(^%1HhTn1nk@10.36.53.63:1121' -e 'mget -c /SZL2/2023/0104/*hq_trade_spot*; exit;'
        // lftp 'jiangyinwhis:HBnh1h*1728(^%1HhTn1nk@10.36.53.63:1121' -e 'mget -c /SZL2/2023/0104/*hq_trade_spot*; exit;'
        // lftp 'jiangyinwhis:HBnh1h*1728(^%1HhTn1nk@10.36.53.63:1121' -e 'get /SZL2/2023/0605/pm_hq_trade_spot.7z.001; exit;'
        
        // let dir_local = "/var/hzs/data/stock/L2Ftp/SZL2/2022/0104";
        // let dir_ftp = "/SZL2/2022/0104";

        info!("\t==== LFTPShell::download_ftpdir: {}, 下载整个FTP文件夹 {dir_ftp}, 到本地 {dir_local} ", TimeFT::now());

        // lftp 'jiangyinwhis:HBnh1h*1728(^%1HhTn1nk@10.36.53.63:1121' -e 'ls /SZL2/2023/0605; exit;'

        let is_本地文件夹是否存在 = path_io::is_dir(&dir_local);
        if !is_本地文件夹是否存在 {
            match std::fs::create_dir_all(&dir_local) {
                Ok(_) => (),
                Err(e) => {
                    info!("\t\t文件夹非法: {dir_local}, 将退出！{:?}", e);
                    return 0;
                },
            }
        }

        let filenames_文件列表_ftp = self.list_files_ftp(&dir_ftp);
        if filenames_文件列表_ftp.len() < 1 {
            info!("\t\tFTP文件夹内无文件: {dir_ftp}, 将退出!");
            return 0;
        }

        // 查缺补漏下载(循环5次)
        for i in 0..count_retry {
            info!("\t第 {i} 次查缺补漏：{}.", TimeFT::now());
            let mut cmd_mget = "mget -c".to_string();
            let mut count_missed = 0;
            for (filename, file_size_ftp) in filenames_文件列表_ftp.iter() {
                let file_local = format!("{dir_local}/{filename}");
                let file_size_local = path_io::file_size(&file_local);
                if file_size_local != *file_size_ftp {
                    cmd_mget.push_str(&format!(" {dir_ftp}/{filename}"));
                    count_missed += 1;
                }
            }
            if count_missed == 0 {
                info!("\t\t所有文件已下载完毕！");
                break;
            }
            // else
            cmd_mget.push_str("; exit;");
            
            info!("\t\t有文件未下载完毕, 将推送下载命令: {cmd_mget}");
            
            let start = TimeFT::now();
            let mut cmd_order = Command::new(LFTP_BIN);

            cmd_order
                .current_dir(&dir_local)
                .arg(&self.account)
                .arg("-e")
                .arg(cmd_mget);

            let output = cmd_order
                .output()
                .expect(&format!("下载【查缺补漏】失败！"));
            io::stdout().write_all(&output.stdout).unwrap();
            io::stderr().write_all(&output.stderr).unwrap();
            let end = TimeFT::now();
            info!(
                "\t\t下载【查缺补漏】完成！{end}, {} secs",
                end.seconds_from(&start) as i32
            );
            thread::sleep(Duration::from_secs(5));
        }
        filenames_文件列表_ftp.len()
    }

    pub fn download_ftpfile(&self, dir_ftp_remote: &str, filename: &str, dir_local: &str, count_retry: u32) {
        info!("\t下载：{dir_ftp_remote}/{filename} 到: {dir_local}, {}", TimeFT::now());
        match std::fs::create_dir_all(&dir_local) {
            Ok(_) => (),
            Err(e) => {
                info!("\t\t文件夹非法: {dir_local}, 将退出！{:?}", e);
                return;
            },
        }

        let file_local = format!("{dir_local}/{filename}");
        for i in 0..count_retry {
            if path_io::is_file(&file_local) {
                info!("\t\t第 {i} 次下载：文件已存在！{}", TimeFT::now());
                break;
            }
            let start = TimeFT::now();
            let mut cmd_order = Command::new(LFTP_BIN);
            cmd_order
                .current_dir(&dir_local)
                .arg(&self.account)
                .arg("-e")
                .arg(format!("get -c {dir_ftp_remote}/{filename}; exit;"));

            let output = cmd_order
                .output()
                .expect(&format!("下载失败！"));
            io::stdout().write_all(&output.stdout).unwrap();
            io::stderr().write_all(&output.stderr).unwrap();
            let end = TimeFT::now();
            info!("\t\t第 {i} 次下载：文件完成！{end}, {} secs",  end.seconds_from(&start) as i32);
            thread::sleep(Duration::from_secs(5));
        }
    }





    
}


#[test]
fn main_lftp_cmd_20230722() {
    const FTP_ACCOUNT: &str = "jiangyinwhis:HBnh1h*1728(^%1HhTn1nk@10.36.53.63:1121";
    let dir_ftp = "/SZL2/2022/0105";
    let dir_local = "/var/hzs/data/stock/L2Ftp/SZL2/2022/0105";

    let lftp = LFTPShell::new(FTP_ACCOUNT.to_string());
    lftp.download_ftpdir(dir_ftp, dir_local, 10);
}